<?php
/**
 * UiReader
 * - Read ui template files and produce source code for View object
 * @author Do Truong Giang
 */
include_once("BaseObject.class.php");
include_once("TplReader.class.php");
include_once(DOCUMENT_ROOT . "/lib/dao/ErrorMessage.class.php");
class UiReader extends BaseObject {
	private $viewInfo;
	private $validateMessage;
	/**
	 * Constructor
	 * - passing the uiFile, read and store information to attributes
	 */
	public function UiReader($uiFile) {
		parent::BaseObject();
		$this->viewInfo = array();
		$this->validateMessage = array();
		$dom = new DomDocument();
		$dom->load($uiFile);
		foreach ($dom->getElementsByTagName("class") as $clazz) {
			// Get the class name
			$className = $clazz->getAttribute("name");
			// Get the codeDef
			$codeDef = $clazz->getAttribute("codeDef");
			// Get the description
			$description = "Codegen auto generated";
			foreach ($clazz->getElementsByTagName("description") as $des) {
				$description = trim($des->textContent);
			}
			// Get the author name
			$author = "Runsystem";
			foreach ($clazz->getElementsByTagName("author") as $auth) {
				$author = trim($auth->textContent);
			}
			// Get the blocks in which we do not want to represent
			foreach ($clazz->getElementsByTagName("remove-block") as $block) {
				$group = explode(",", $block->getAttribute("group"));
			}
			// Get the property information
			$property = array();
			foreach ($clazz->getElementsByTagName("property") as $prop) {
				$property[] = array("name" => $prop->getAttribute("name"),
									"field" => $prop->getAttribute("field"),
									"type" => $prop->getAttribute("type"),
									"required" => $prop->getAttribute("required"),
									"display" => $prop->getAttribute("display"),
									"style" => $prop->getAttribute("style"),
									"class" => $prop->getAttribute("class"),
									"row" => $prop->getAttribute("row"),
									"col" => $prop->getAttribute("col"),
									"list" => $prop->getAttribute("list"),
									"codeDef" => $prop->getAttribute("codeDef"),
									"validateType" => $prop->getAttribute("validateType"),
									"size" => $prop->getAttribute("size"),
									"minSize" => $prop->getAttribute("min-size"),
									"className" => $className
									);
			}
			$this->viewInfo[] = array( "className" => $className,
									"codeDef" => $codeDef,
									"description" => $description,
									"author" => $author,
									"property" => $property,
									"blockGroup" => $group,
									);
		}
	}
	/**
	 * generateCode
	 * - Generate the source code for ui file
	 * - Before generating, validate the XML file
	 */
	public function generateCode() {
		$this->validateXml();
		$this->showError();
		if ($this->hasError()) {
			return;
		}
		$tplReader = new TplReader();
		foreach ($this->viewInfo as $view) {
			$params = array("CLASS_NAME" => $view["className"],
							"INCLUDE_CODE_DEF" => $this->includeCodeDef($view),
							"DESCRIPTION" => $view["description"],
							"AUTHOR" => $view["author"],
							"GENERATED_TIME" => date("Y-m-d H:i:s"),
							"LIST_ATTRIBUTES" => $this->getListAttributes($view),
							"PROPERTY_UPPER" => $this->getPropertyUpper($view),
							"GET_HTML_OF" => $this->getFunctionGetHtmlOf($view),
							"GET_DISPLAY_OF" => $this->getFunctionGetDisplayOf($view),
							"DELIMITER" => $this->getDelimiter($view),
							"HIDDEN_TAG_OF_ALL" => $this->getFunctionGetHiddenTagOfAll($view),
							"VALIDATE" => $this->getFunctionValidate($view),
							"SET_VIEW_FROM_MODEL" => $this->getFunctionSetViewFromModel($view),
							"SET_MODEL_FROM_VIEW" => $this->getFunctionSetModelFromView($view),
							);
			$srcCode = $tplReader->read(DOCUMENT_ROOT . "/codegen/templates/ui_template.xml", $params, $view["blockGroup"]);
			$this->storeUiSourceCode($srcCode, $view["className"]);
			$this->storeValidateMessage();
		}
		
	}
	/**
	 * includeCodeDef
	 * - A string represents the inclusion of codeDef to the object
	 */
	public function includeCodeDef($view) {
		$codeDef = $view["codeDef"];
		// If we do not use a code def, simple return nothing
		if ($codeDef == "") {
			return "";
		}
		// Otherwise, we have to extract $codeDef to include all codeDef files
		$code = "";
		// Explode the codeDef to get the list of codeDef files
		$fileList = explode(",", $codeDef);
		foreach ($fileList as $file) {
			$code .= "include_once(DOCUMENT_ROOT . \"/lib/ui/res/$file.php\");\n";
		}
		return $code;
	}
	/**
	 * getListAttributes
	 * - Return the list of attributes of a view, separated by comma
	 * - Read the viewInfo[][property]
	 */
	private function getListAttributes($view) {
		$listArr = array();
		foreach ($view["property"] as $prop) {
			$listArr[] = "\"" . $this->underScoreToUpperCase($prop["name"]) . "\"";
		}
		return implode(",", $listArr);
	}
	/**
	 * getPropertyUpper
	 * - Return the array of property in camel format
	 */
	private function getPropertyUpper($view) {
		$propUpper = array();
		foreach ($view["property"] as $prop) {
			$propUpper[] = $this->camelFormat($prop["name"]);
		}
		return $propUpper;
	}
	/**
	 * getDelimiter
	 * - Return string $delimiter if property is a checkbox
	 * - Otherwise, return empty
	 */
	function getDelimiter($view) {
		$code = array();
		foreach ($view["property"] as $prop) {
			if ($prop["type"] == "checkbox") {
				$code[] = "\$delimiter = null";
			}
			else {
				$code[] = "";
			} 
		}
		return $code;
	}
	/**
	 * getFunctionGetHtmlOf
	 * - Return the content of function getHtmlOfxxx
	 */
	private function getFunctionGetHtmlOf($view) {
		$code = "";
		foreach ($view["property"] as $prop) {
			switch ($prop["type"]) {
				case "text":
					$code[] = $this->getFunctionGetHtmlOfText($prop);
					break;
				case "password":
					$code[] = $this->getFunctionGetHtmlOfPassword($prop);
					break;
				case "textarea":
					$code[] = $this->getFunctionGetHtmlOfTextArea($prop);
					break;
				case "select":
					$code[] = $this->getFunctionGetHtmlOfSelect($prop);
					break;
				case "radio":
					$code[] = $this->getFunctionGetHtmlOfRadio($prop);
					break;
				case "checkbox":
					$code[] = $this->getFunctionGetHtmlOfCheckbox($prop);
					break;
				case "file":
					$code[] = $this->getFunctionGetHtmlOfFile($prop);
					break;
			}
		}
		return $code;
	}
	/**
	 * getFunctionGetDisplayOf
	 * - Return the content of function getHtmlOfxxx
	 */
	private function getFunctionGetDisplayOf($view) {
		$code = "";
		foreach ($view["property"] as $prop) {
			switch ($prop["type"]) {
				case "text":
					$code[] = $this->getFunctionGetDisplayOfText($prop);
					break;
				case "password":
					$code[] = $this->getFunctionGetDisplayOfPassword($prop);
					break;
				case "textarea":
					$code[] = $this->getFunctionGetDisplayOfTextArea($prop);
					break;
				case "select":
					$code[] = $this->getFunctionGetDisplayOfSelect($prop);
					break;
				case "radio":
					$code[] = $this->getFunctionGetDisplayOfRadio($prop);
					break;
				case "checkbox":
					$code[] = $this->getFunctionGetDisplayOfCheckbox($prop);
					break;
				case "file":
					$code[] = $this->getFunctionGetDisplayOfFile($prop);
					break;
			}
		}
		return $code;
	}
	/**
	 * getFunctionGetHtmlOfText
	 * - Return the content of function getHtmlOfxxx where xxx is a text field
	 */
	private function getFunctionGetHtmlOfText($prop) {
		$code = "";
		$name = $this->underScoreToUpperCase($prop["name"]);
		$style = $prop["style"];
		$class = $prop["class"];
		$code .= "\$html = '<input type=\"text\" name=\"$name\" id=\"$name\" value=\"' . \$this->getAttribute(\"$name\"). '\" style=\"$style\" class=\"$class\" ' . \$additional . '>';\n";
		$code .= "		\$html .= \$this->postShowHtml('$name');\n";
		$code .= "		return \$html;\n";
		return $code;
	}
	/**
	 * getFunctionGetHtmlOfPassword
	 * - Return the content of function getHtmlOfxxx where xxx is a password field
	 */
	private function getFunctionGetHtmlOfPassword($prop) {
		$code = "";
		$name = $this->underScoreToUpperCase($prop["name"]);
		$style = $prop["style"];
		$class = $prop["class"];
		$code .= "\$html = '<input type=\"password\" name=\"$name\" id=\"$name\" value=\"' . \$this->getAttribute(\"$name\"). '\" style=\"$style\" class=\"$class\" ' . \$additional . '>';\n";
		$code .= "		\$html .= \$this->postShowHtml('$name');\n";
		$code .= "		return \$html;\n";
		return $code;
	}
	/**
	 * getFunctionGetHtmlOfTextArea
	 * - Return the content of function getHtmlOfxxx where xxx is a textarea
	 */
	private function getFunctionGetHtmlOfTextArea($prop) {
		$code = "";
		$name = $this->underScoreToUpperCase($prop["name"]);
		$style = $prop["style"];
		$class = $prop["class"];
		$row = $prop["row"];
		$col = $prop["col"];
		$code .= "\$html = '<textarea cols=\"$col\" rows=\"$row\" name=\"$name\" id=\"$name\" style=\"$style\" class=\"$class\" ' . \$additional . '>' . \$this->getAttribute(\"$name\") . '</textarea>';\n";
		$code .= "		\$html .= \$this->postShowHtml('$name');\n";
		$code .= "		return \$html;";
		return $code;
	}
	/**
	 * getFunctionGetHtmlOfSelect
	 * - Return the content of function getHtmlOfxxx where xxx is a select box
	 */
	private function getFunctionGetHtmlOfSelect($prop) {
		$code = "";
		$name = $this->underScoreToUpperCase($prop["name"]);
		$style = $prop["style"];
		$class = $prop["class"];
		$list = $prop["list"];
		$codeDef = $prop["codeDef"];
		// The codeDef has higher property to list
		if ($codeDef != "") {
			$code .= "\$selectInfo = \$this->getCodeDef(\"$codeDef\");\n";
		}
		// We extract the list to get a string
		else {
			$option = explode("|", $list);
			$innerStr = array();
			foreach ($option as $opt) {
				list($key, $value) = explode(":", $opt);
				$innerStr[] = '"' . $key . '" => "' . $value . '"';
			}
			$code .= "\$selectInfo = array(" . implode(",", $innerStr) . ");\n";
		}
		// Now, the real content
		$code .= "		\$html = '<select name=\"$name\" id=\"$name\" class=\"$class\" style=\"$style\" ' . \$additional . '>';\n";
		$code .= "		foreach (\$selectInfo as \$key => \$value) {\n";
		$code .= "			\$selected = \"\";\n";
		$code .= "			if (\$key == \$this->getAttribute(\"$name\")) {\n";
		$code .= "				\$selected = \" selected\";\n";
		$code .= "			}\n";
		$code .= "			\$html .= '<option value=\"' . \$key . '\"' . \$selected . '>' . \$value . '</option>';\n";
		$code .= "		}\n";
		$code .= "		\$html .= '</select>';\n";
		$code .= "		\$html .= \$this->postShowHtml('$name');\n";
		$code .= "		return \$html;";
		return $code;
	}
	/**
	 * getFunctionGetHtmlOfRadio
	 * - Return the content of function getHtmlOfxxx where xxx is a radio
	 */
	private function getFunctionGetHtmlOfRadio($prop) {
		$code = "";
		$name = $this->underScoreToUpperCase($prop["name"]);
		$style = $prop["style"];
		$class = $prop["class"];
		$col = $prop["col"];
		$list = $prop["list"];
		$codeDef = $prop["codeDef"];
		// The codeDef has higher property to list
		if ($codeDef != "") {
			$code .= "\$radioInfo = \$this->getCodeDef(\"$codeDef\");\n";
		}
		// We extract the list to get a string
		else {
			$option = explode("|", $list);
			$innerStr = array();
			foreach ($option as $opt) {
				list($key, $value) = explode(":", $opt);
				$innerStr[] = '"' . $key . '" => "' . $value . '"';
			}
			$code .= "\$radioInfo = array(" . implode(",", $innerStr) . ");\n";
		}
		// Now, the real content
		$code .= "		\$noOfCols = $col;\n";
		$code .= "		\$i = 0;\n";
		$code .= "		\$html = '<table width=\"100%\" cellspacing=\"0\" cellpadding=\"0\" class=\"$class\" style=\"$style\">';\n";
		$code .= "		foreach (\$radioInfo as \$key => \$value) {\n";
		$code .= "			if (\$i % \$noOfCols == 0) {\n";
		$code .= "				\$html .= '<tr>';\n";
		$code .= "			}\n";
		$code .= "			\$i++;\n";
		$code .= "			\$html .= '<td>';\n";
		$code .= "			\$checked = '';\n";
		$code .= "			if (\$key == \$this->getAttribute('$name')) {\n";
		$code .= "				\$checked = ' checked';\n";
		$code .= "			}\n";
		$code .= "			\$html .= '<input type=\"radio\" name=\"$name\" id=\"$name\" value=\"' . \$key . '\"' . \$checked . \$additional . '>' . \$value;\n";
		$code .= "			\$html .= '</td>';\n";
		$code .= "			if (\$i % \$noOfCols == 0) {\n";
		$code .= "				\$html .= '</tr>';\n";
		$code .= "			}\n";
		$code .= "		}\n";
		$code .= "		while (\$i % \$noOfCols != 0) {\n";
		$code .= "			\$i++;\n";
		$code .= "			\$html .= '<td>&nbsp;</td>';\n";
		$code .= "			if (\$i % \$noOfCols == 0) {\n";
		$code .= "				\$html .= '</tr>';\n";
		$code .= "			}\n";
		$code .= "		}\n";
		$code .= "		\$html .= '</table>';\n";
		$code .= "		\$html .= \$this->postShowHtml('$name');\n";
		$code .= "		return \$html;";
		return $code;
	}
	/**
	 * getFunctionGetHtmlOfCheckbox
	 * - Return the content of function getHtmlOfxxx where xxx is a checkbox
	 */
	private function getFunctionGetHtmlOfCheckbox($prop) {
		$code = "";
		$name = $this->underScoreToUpperCase($prop["name"]);
		$style = $prop["style"];
		$class = $prop["class"];
		$col = $prop["col"];
		$list = $prop["list"];
		$codeDef = $prop["codeDef"];
		// The codeDef has higher property to list
		if ($codeDef != "") {
			$code .= "\$checkboxInfo = \$this->getCodeDef(\"$codeDef\");\n";
		}
		// We extract the list to get a string
		else {
			$option = explode("|", $list);
			$innerStr = array();
			foreach ($option as $opt) {
				list($key, $value) = explode(":", $opt);
				$innerStr[] = '"' . $key . '" => "' . $value . '"';
			}
			$code .= "\$checkboxInfo = array(" . implode(",", $innerStr) . ");\n";
		}
		// Now, the real content
		$code .= "		\$asArray = '';\n";
		$code .= "		if (count(\$checkboxInfo) > 1) {\n";
		$code .= "			\$asArray = '[]';\n";
		$code .= "		}\n";
		$code .= "		\$noOfCols = $col;\n";
		$code .= "		\$i = 0;\n";
		$code .= "		if (is_array(\$this->getAttribute('$name'))) {\n";
		$code .= "			\$selectedValues = \$this->getAttribute('$name');\n";
		$code .= "		}\n";
		$code .= "		else {\n";
		$code .= "			\$selectedValues = array(\$this->getAttribute('$name'));\n";
		$code .= "		}\n";
		$code .= "		\$html = '<table width=\"100%\" cellspacing=\"0\" cellpadding=\"0\" class=\"$class\" style=\"$style\">';\n";
		$code .= "		foreach (\$checkboxInfo as \$key => \$value) {\n";
		$code .= "			if (\$i % \$noOfCols == 0) {\n";
		$code .= "				\$html .= '<tr>';\n";
		$code .= "			}\n";
		$code .= "			\$i++;\n";
		$code .= "			\$html .= '<td>';\n";
		$code .= "			\$checked = '';\n";
		$code .= "			if (in_array(\$key, \$selectedValues)) {\n";
		$code .= "				\$checked = ' checked';\n";
		$code .= "			}\n";
		$code .= "			\$html .= '<input type=\"checkbox\" name=\"$name' . \$asArray . '\" id=\"$name\" value=\"' . \$key . '\"' . \$checked . \$additional . '>' . \$value;\n";
		$code .= "			\$html .= '</td>';\n";
		$code .= "			if (\$i % \$noOfCols == 0) {\n";
		$code .= "				\$html .= '</tr>';\n";
		$code .= "			}\n";
		$code .= "		}\n";
		$code .= "		while (\$i % \$noOfCols != 0) {\n";
		$code .= "			\$i++;\n";
		$code .= "			\$html .= '<td>&nbsp;</td>';\n";
		$code .= "			if (\$i % \$noOfCols == 0) {\n";
		$code .= "				\$html .= '</tr>';\n";
		$code .= "			}\n";
		$code .= "		}\n";
		$code .= "		\$html .= '</table>';\n";
		$code .= "		\$html .= \$this->postShowHtml('$name');\n";
		$code .= "		return \$html;";
		return $code;
	}
	/**
	 * getFunctionGetHtmlOfFile
	 * - Return the &lt;input type='file'&gt; tag
	 */
	private function getFunctionGetHtmlOfFile($prop) {
		$code = "";
		$name = $this->underScoreToUpperCase($prop["name"]);
		$style = $prop["style"];
		$class = $prop["class"];
		$code .= "\$html = '<input type=\"file\" name=\"$name\" id=\"$name\" style=\"$style\" class=\"$class\" ' . \$additional . '>';\n";
		$code .= "		return \$html;";
		return $code;
		
	}
	/**
	 * getFunctionGetDisplayOfText
	 * - Return the content of getDislayOfxxx where xxx is a text
	 */
	private function getFunctionGetDisplayOfText($prop) {
		$name = $this->underScoreToUpperCase($prop["name"]);
		$code = "\$html = \$this->getAttribute('$name');\n";
		$code .= "		return \$html;";
		return $code;
	}
	/**
	 * getFunctionGetDisplayOfPassword
	 * - Return the content of getDislayOfxxx where xxx is a password
	 */
	private function getFunctionGetDisplayOfPassword($prop) {
		$name = $this->underScoreToUpperCase($prop["name"]);
		$code .= "\$html = '';\n";
		$code .= "		\$c = strlen(\$this->getAttribute('$name'));\n";
		$code .= "		for (\$i = 0; \$i < \$c; \$i++) {\n";
		$code .= "			\$html .= '*';\n";
		$code .= "		}\n";
		$code .= "		return \$html;";
		return $code;
	}
	/**
	 * getFunctionGetDisplayOfTextArea
	 * - Return the content of getDislayOfxxx where xxx is a textarea
	 */
	private function getFunctionGetDisplayOfTextArea($prop) {
		$name = $this->underScoreToUpperCase($prop["name"]);
		$code = "\$html = nl2br(\$this->getAttribute('$name'));\n";
		$code .= "		return \$html;";
		return $code;
	}
	/**
	 * getFunctionGetDisplayOfSelect
	 * - Return the content of getDislayOfxxx where xxx is a select
	 */
	private function getFunctionGetDisplayOfSelect($prop) {
		$code = "";
		$name = $this->underScoreToUpperCase($prop["name"]);
		$list = $prop["list"];
		$codeDef = $prop["codeDef"];
		// The codeDef has higher property to list
		if ($codeDef != "") {
			$code .= "\$selectInfo = \$this->getCodeDef(\"$codeDef\");\n";
		}
		// We extract the list to get a string
		else {
			$option = explode("|", $list);
			$innerStr = array();
			foreach ($option as $opt) {
				list($key, $value) = explode(":", $opt);
				$innerStr[] = '"' . $key . '" => "' . $value . '"';
			}
			$code .= "\$selectInfo = array(" . implode(",", $innerStr) . ");\n";
		}
		// Now, the real content
		$code .= "		return \$selectInfo[\$this->getAttribute('$name')];";
		return $code;
	}
	/**
	 * getFunctionGetDisplayOfRadio
	 * - Return the content of function getDisplayOfxxx where xxx is a radio
	 */
	private function getFunctionGetDisplayOfRadio($prop) {
		$code = "";
		$name = $this->underScoreToUpperCase($prop["name"]);
		$list = $prop["list"];
		$codeDef = $prop["codeDef"];
		// The codeDef has higher property to list
		if ($codeDef != "") {
			$code .= "\$radioInfo = \$this->getCodeDef(\"$codeDef\");\n";
		}
		// We extract the list to get a string
		else {
			$option = explode("|", $list);
			$innerStr = array();
			foreach ($option as $opt) {
				list($key, $value) = explode(":", $opt);
				$innerStr[] = '"' . $key . '" => "' . $value . '"';
			}
			$code .= "\$radioInfo = array(" . implode(",", $innerStr) . ");\n";
		}
		// Now, the real content
		$code .= "		return \$radioInfo[\$this->getAttribute('$name')];";
		return $code;
	}
	/**
	 * getFunctionGetDisplayOfCheckbox
	 * - Return the content of function getDisplayOfxxx where xxx is a checkbox
	 */
	private function getFunctionGetDisplayOfCheckbox($prop) {
		$code = "";
		$name = $this->underScoreToUpperCase($prop["name"]);
		$list = $prop["list"];
		$codeDef = $prop["codeDef"];
		// The codeDef has higher property to list
		if ($codeDef != "") {
			$code .= "\$checkboxInfo = \$this->getCodeDef(\"$codeDef\");\n";
		}
		// We extract the list to get a string
		else {
			$option = explode("|", $list);
			$innerStr = array();
			foreach ($option as $opt) {
				list($key, $value) = explode(":", $opt);
				$innerStr[] = '"' . $key . '" => "' . $value . '"';
			}
			$code .= "\$checkboxInfo = array(" . implode(",", $innerStr) . ");\n";
		}
		// Now, the real content
		$code .= "		\$delimiter = (\$delimiter == null ? ',' : \$delimiter);\n";
		$code .= "		if (is_array(\$this->getAttribute('$name'))) {\n";
		$code .= "			\$selectedValues = \$this->getAttribute('$name');\n";
		$code .= "		}\n";
		$code .= "		else {\n";
		$code .= "			\$selectedValues = array(\$this->getAttribute('$name'));\n";
		$code .= "		}\n";
		$code .= "		\$html = '';\n";
		$code .= "		\$c = count(\$selectedValues);\n";
		$code .= "		\$i = 0;\n";
		$code .= "		foreach (\$selectedValues as \$value) {\n";
		$code .= "			\$html .= \$checkboxInfo[\$value];\n";
		$code .= "			\$i++;\n";
		$code .= "			if (\$i < \$c) {\n";
		$code .= "				\$html .= \$delimiter;\n";
		$code .= "			}\n";
		$code .= "		}\n";
		$code .= "		return \$html;";
		return $code;
	}
	/**
	 * getFunctionGetDisplayOfFile
	 * - Return the path of file
	 */
	private function getFunctionGetDisplayOfFile($prop) {
		$name = $this->underScoreToUpperCase($prop["name"]);
		$code = "return \$this->getAttribute(\"$name\");";
		return $code;
	}
	/**
	 * getFunctionGetHiddenTagOfAll
	 * - Return the content of function getHiddenTagOfAll
	 */
	private function getFunctionGetHiddenTagOfAll($view) {
		$code = array();
		foreach ($view["property"] as $prop) {
			switch ($prop["type"]) {
				case "text":
					$code[] = $this->getHiddenTagOfText($prop);
					break;
				case "password":
					$code[] = $this->getHiddenTagOfPassword($prop);
					break;
				case "textarea":
					$code[] = $this->getHiddenTagOfTextArea($prop);
					break;
				case "select":
					$code[] = $this->getHiddenTagOfSelect($prop);
					break;
				case "radio":
					$code[] = $this->getHiddenTagOfRadio($prop);
					break;
				case "checkbox":
					$code[] = $this->getHiddenTagOfCheckbox($prop);
					break;
				case "file":
					$code[] = $this->getHiddenTagOfFile($prop);
			}
		}
		return $code;
	}
	/**
	 * getHiddenTagOfText
	 * - Return the hidden tag of a text
	 */
	private function getHiddenTagOfText($prop) {
		$name = $this->underScoreToUpperCase($prop["name"]);
		$code = "\$html .= '<input type=\"hidden\" name=\"$name\" id=\"$name\" value=\"' . str_replace('\"', '\\\"', \$this->getAttribute('$name')) . '\">';";
		return $code;
	}
	/** 
	 * getHiddenTagOfPassword
	 * - Return the hidden tag of a password
	 */
	private function getHiddenTagOfPassword($prop) {
		$name = $this->underScoreToUpperCase($prop["name"]);
		$code = "\$html .= '<input type=\"hidden\" name=\"$name\" id=\"$name\" value=\"' . \$this->getAttribute('$name') . '\">';";
		return $code;
	}
	/**
	 * getHiddenTagOfTextArea
	 * - Return the hidden tag of a textarea
	 */
	private function getHiddenTagOfTextArea($prop) {
		$name = $this->underScoreToUpperCase($prop["name"]);
		$code = "\$html .= '<input type=\"hidden\" name=\"$name\" id=\"$name\" value=\"' . \$this->getAttribute('$name') . '\">';";
		return $code;
	}
	/**
	 * getHiddenTagOfSelect
	 * - Return the hidden tag of select
	 */
	private function getHiddenTagOfSelect($prop) {
		$name = $this->underScoreToUpperCase($prop["name"]);
		$code = "\$html .= '<input type=\"hidden\" name=\"$name\" id=\"$name\" value=\"' . \$this->getAttribute('$name') . '\">';";
		return $code;
	}
	/**
	 * getHiddenTagRadio
	 * - Return the hidden tag of a radio
	 */
	private function getHiddenTagOfRadio($prop) {
		$name = $this->underScoreToUpperCase($prop["name"]);
		$code = "\$html .= '<input type=\"hidden\" name=\"$name\" id=\"$name\" value=\"' . \$this->getAttribute('$name') . '\">';";
		return $code;
	}
	/**
	 * getHiddenTagOfCheckbox
	 * - Return the hidden tag of a checkbox
	 */
	private function getHiddenTagOfCheckbox($prop) {
		$name = $this->underScoreToUpperCase($prop["name"]);
		$code = "\$selectedValues = \$this->getAttribute(\"$name\");\n";
		$code .= "		if (is_array(\$selectedValues)) {\n";
		$code .= "			foreach (\$selectedValues as \$value) {\n";
		$code .= "				\$html .= '<input type=\"hidden\" name=\"" . $name . "[]\" id=\"$name\" value=\"' . \$value . '\">';\n";
		$code .= "			}\n";
		$code .= "		}\n";
		$code .= "		else if (\$selectedValues !== null){\n";
		$code .= "			\$html .= '<input type=\"hidden\" name=\"$name\" id=\"$name\" value=\"' . \$selectedValues . '\">';\n";
		$code .= "		}";
		return $code;
	}
	/**
	 * getHiddenTagOfFile
	 * - Return the hidden tag of a file
	 */
	private function getHiddenTagOfFile($prop) {
		$name = $this->underScoreToUpperCase($prop["name"]);
		$code = "\$html .= '<input type=\"hidden\" name=\"$name\" id=\"$name\" value=\"' . \$this->getAttribute(\"$name\") . '\">';";
		return $code;
	}
	/**
	 * getFunctionValidate
	 * - Return the content of validate function
	 */
	private function getFunctionValidate($view) {
		$code = array();
		foreach ($view["property"] as $prop) {
			switch ($prop["type"]) {
				case "text":
					$code[] = $this->getValidateText($prop);
					break;
				case "password":
					$code[] = $this->getValidatePassword($prop);
					break;
				case "textarea":
					$code[] = $this->getValidateTextArea($prop);
					break;
				case "select":
					$code[] = $this->getValidateSelect($prop);
					break;
				case "radio":
					$code[] = $this->getValidateRadio($prop);
					break;
				case "checkbox":
					$code[] = $this->getValidateCheckbox($prop);
					break;
				case "file":
					$code[] = $this->getValidateFile($prop);
			}
		}
		return $code;
	}
	/**
	 * getValidateText
	 * - Return the validation of a text
	 */
	private function getValidateText($prop) {
		$name = $this->underScoreToUpperCase($prop["name"]);
		$required = $prop["required"];
		$size = $prop["size"];
		$minSize = $prop["minSize"];
		$validateType = $prop["validateType"];
		$display = $prop["display"];
		$className = $prop["className"];
		if ($required == "true") {
			$code = "		if (\$this->getAttribute('$name') === null) {\n";
			$code .= "			\$this->addError('$name', 1);\n";
			$code .= "		}\n";
			$this->addRequireMessage($className, $name, 1, $display);
		}
		if ($validateType != "") {
			$code .= "		if (Validator::is$validateType(\$this->getAttribute('$name')) === false) {\n";
			$code .= "			\$this->addError('$name', 2);\n";
			$code .= "		}\n";
			$this->addValidateTypeMessage($className, $name, 2, $display, $validateType);
		}
		if ($size != "") {
			$code .= "		if (strlen(\$this->getAttribute('$name')) > $size) {\n";
			$code .= "			\$this->addError('$name', 3);\n";
			$code .= "		}\n";
			$this->addSizeMessage($className, $name, 3, $display, $size);
		}
		if ($minSize != "") {
			$code .= "		if (strlen(\$this->getAttribute('$name')) < $minSize) {\n";
			$code .= "			\$this->addError('$name', 4);\n";
			$code .= "		}\n";
			$this->addMinSizeMessage($className, $name, 4, $display, $minSize);
		}
		return $code;
	}
	/**
	 * getValidatePassword
	 * - Return the validation of a text
	 */
	private function getValidatePassword($prop) {
		$name = $this->underScoreToUpperCase($prop["name"]);
		$required = $prop["required"];
		$size = $prop["size"];
		$minSize = $prop["minSize"];
		$validateType = $prop["validateType"];
		$display = $prop["display"];
		$className = $prop["className"];
		if ($required == "true") {
			$code = "		if (\$this->getAttribute('$name') === null) {\n";
			$code .= "			\$this->addError('$name', 1);\n";
			$code .= "		}\n";
			$this->addRequireMessage($className, $name, 1, $display);
		}
		if ($validateType != "") {
			$code .= "		if (Validator::is$validateType(\$this->getAttribute('$name')) === false) {\n";
			$code .= "			\$this->addError('$name', 2);\n";
			$code .= "		}\n";
			$this->addValidateTypeMessage($className, $name, 2, $display, $validateType);
		}
		if ($size != "") {
			$code .= "		if (strlen(\$this->getAttribute('$name')) > $size) {\n";
			$code .= "			\$this->addError('$name', 3);\n";
			$code .= "		}\n";
			$this->addSizeMessage($className, $name, 3, $display, $size);
		}
		if ($minSize != "") {
			$code .= "		if (strlen(\$this->getAttribute('$name')) < $minSize) {\n";
			$code .= "			\$this->addError('$name', 4);\n";
			$code .= "		}\n";
			$this->addMinSizeMessage($className, $name, 4, $display, $minSize);
		}
		return $code;
	}
	/**
	 * getValidateTextArea
	 * - Return the validation of textarea
	 */
	private function getValidateTextArea($prop) {
		$name = $this->underScoreToUpperCase($prop["name"]);
		$required = $prop["required"];
		$size = $prop["size"];
		$minSize = $prop["minSize"];
		$validateType = $prop["validateType"];
		$display = $prop["display"];
		$className = $prop["className"];
		$code = "";
		if ($required == "true") {
			$code = "		if (\$this->getAttribute('$name') === null) {\n";
			$code .= "			\$this->addError('$name', 1);\n";
			$code .= "		}\n";
			$this->addRequireMessage($className, $name, 1, $display);
		}
		if ($validateType != "") {
			$code .= "		if (Validator::is$validateType(\$this->getAttribute('$name')) === false) {\n";
			$code .= "			\$this->addError('$name', 2);\n";
			$code .= "		}\n";
			$this->addValidateTypeMessage($className, $name, 2, $display, $validateType);
		}
		if ($size != "") {
			$code .= "		if (strlen(\$this->getAttribute('$name')) > $size) {\n";
			$code .= "			\$this->addError('$name', 3);\n";
			$code .= "		}\n";
			$this->addSizeMessage($className, $name, 3, $display, $size);
		}
		if ($minSize != "") {
			$code .= "		if (strlen(\$this->getAttribute('$name')) < $minSize) {\n";
			$code .= "			\$this->addError('$name', 4);\n";
			$code .= "		}\n";
			$this->addMinSizeMessage($className, $name, 4, $display, $minSize);
		}
		return $code;
	}
	/**
	 * getValidateSelect
	 * - Return the validation of select
	 */
	private function getValidateSelect($prop) {
		$name = $this->underScoreToUpperCase($prop["name"]);
		$required = $prop["required"];
		$display = $prop["display"];
		$className = $prop["className"];
		$code = "";
		if ($required == "true") {
			$code = "		if (\$this->getAttribute('$name') === null) {\n";
			$code .= "			\$this->addError('$name', 1);\n";
			$code .= "		}\n";
			$this->addRequireMessage($className, $name, 1, $display);
		}
		return $code;
	}
	/**
	 * getValidateRadio
	 * - Return the validation of radio
	 */
	private function getValidateRadio($prop) {
		$name = $this->underScoreToUpperCase($prop["name"]);
		$required = $prop["required"];
		$display = $prop["display"];
		$className = $prop["className"];
		$code = "";
		if ($required == "true") {
			$code = "		if (\$this->getAttribute('$name') === null) {\n";
			$code .= "			\$this->addError('$name', 1);\n";
			$code .= "		}\n";
			$this->addRequireMessage($className, $name, 1, $display);
		}
		return $code;
	}
	/**
	 * getValidateCheckbox
	 * - Return the validation of checkbox
	 */
	private function getValidateCheckbox($prop) {
		$name = $this->underScoreToUpperCase($prop["name"]);
		$required = $prop["required"];
		$display = $prop["display"];
		$className = $prop["className"];
		$code = "";
		if ($required == "true") {
			$code = "		if (\$this->getAttribute('$name') === null) {\n";
			$code .= "			\$this->addError('$name', 1);\n";
			$code .= "		}\n";
			$this->addRequireMessage($className, $name, 1, $display);
		}
		return $code;
	}
	/**
	 * getValidateFile
	 * - Return the validation of file
	 */
	private function getValidateFile($prop) {
		$name = $this->underScoreToUpperCase($prop["name"]);
		$required = $prop["required"];
		$display = $prop["display"];
		$className = $prop["className"];
		$code = "";
		if ($required == "true") {
			$code = "		if (!isset(\$_FILES['$name'])) {\n";
			$code .= "			\$this->addError('$name', 1);\n";
			$code .= "		}\n";
			$this->addRequireMessage($className, $name, 1, $display);
		}
		return $code;
	}
	/**
	 * addRequireMessage
	 * - Add the require message to list of error message
	 * @param String $display The friendly name of field
	 */
	private function addRequireMessage($className, $name, $code, $display) {
		$this->validateMessage[] = array($className, $name, $code, "「" . $display . "」が必須です。");
	}
	/**
	 * addValidateTypeMessage
	 * - Add the validate type error message
	 * @param String $display The name of field
	 * @param String $type The correct type
	 */
	private function addValidateTypeMessage($className, $name, $code, $display, $type) {
		$this->validateMessage[] = array($className, $name, $code, "「" . $display .  "」が正しくありません。");
	}
	/**
	 * addSizeMessage
	 * - Add the size error message
	 * @param String $display The friendly name of field
	 * @param String $size The maximum size of field
	 */
	private function addSizeMessage($className, $name, $code, $display, $size) {
		$this->validateMessage[] = array($className, $name, $code, "「" . $display . "」が長すぎです。" . $size . "以内で入力して下さい。");
	}
	/**
	 * addMinSizeMessage
	 * - Add the min size error message
	 * @param String $display The friendly name of field
	 * @param String $size The minimum size of field
	 */
	private function addMinSizeMessage($className, $name, $code, $display, $size) {
		$this->validateMessage[] = array($className, $name, $code, "「" . $display . "」が短すぎです。" . $size . "以上で入力して下さい。");
	}
	/**
	 * getFunctionSetViewFromModel
	 * - Return the content of function setViewFromModel
	 */
	private function getFunctionSetViewFromModel($view) {
		$modelMapping = $this->fetchModelMapping($view);
		$code = "";
		foreach ($modelMapping as $tableName => $fields) {
			$code .= "		if (\$tableName === '$tableName') {\n";
			foreach ($fields as $columnInfo) {
				$columnName = $columnInfo[0];
				$pageElement = $columnInfo[1];
				$code .= "			\$this->setAttribute('$pageElement', \$model->getAttribute('$columnName'));\n";
			}
			$code .= "		}\n";
		}
		return $code;
	}
	/**
	 * getFunctionSetModelFromView
	 * - Return the content of function setModelFromView
	 */
	private function getFunctionSetModelFromView($view) {
		$modelMapping = $this->fetchModelMapping($view);
		$code = "";
		foreach ($modelMapping as $tableName => $fields) {
			$code .= "		if (\$tableName === '$tableName') {\n";
			foreach ($fields as $columnInfo) {
				$columnName = $columnInfo[0];
				$pageElement = $columnInfo[1];
				$code .= "			\$model->setAttribute('$columnName', \$this->getAttribute('$pageElement'));\n";
			}
			$code .= "		}\n";
		}
		return $code;
	}
	/**
	 * fetchModelMapping
	 * - Serve the getFunctionSetViewFromModel and getFunctionSetModelFromView
	 * - Return the mapping between page elements and fields in DB
	 */
	private function fetchModelMapping($view) {
		$map = array();
		foreach ($view["property"] as $prop) {
			$name = $this->underScoreToUpperCase($prop["name"]);
			$field = $prop["field"];
			list($tableName, $fieldName) = explode(".", $field);
			if (!isset($map[$tableName])) {
				$map[$tableName] = array();
			}
			$map[$tableName][] = array($fieldName, $name);
		}
		return $map;
	}
	/**
	 * storeValidateMessage
	 * - Store the validate message to DB
	 */
	private function storeValidateMessage() {
		$classes = array();
		foreach ($this->validateMessage as $messInfo) {
			$classes[] = $messInfo[0];
		}
		$classes = array_unique($classes);
		$errorMessage = new ErrorMessage();
		$errorMessage->removeMessageOfClasses($classes);
		foreach ($this->validateMessage as $messInfo) {
			$objectName = $messInfo[0];
			$fieldName = $messInfo[1];
			$errorCode = $messInfo[2];
			$message = $messInfo[3];
			$model = new ErrorMessage();
			$model->setAttribute("object_name", $objectName);
			$model->setAttribute("field_name", $fieldName);
			$model->setAttribute("error_code", $errorCode);
			$model->setAttribute("message", $message);
			$model->insert();
		}
	}
	/**
	 * validateXml
	 * - Validate file XML to prevent some potential errors
	 */
	private function validateXml() {
		foreach ($this->viewInfo as $view) {
			$i = 0;
			$className = $view["className"];
			// Check if class name is correct
			$firstChar = substr($className, 0, 1); 
			if ($firstChar < 'A' || $firstChar > 'Z') {
				$this->addWarning("$className : Class name is not good");
			}
			foreach ($view["property"] as $property) {
				$i++;
				$this->checkGeneralSyntax($className, $i, $property);
				switch ($property["type"]) {
					case "text":
						$this->checkTextSyntax($className, $i, $property);
						break;
					case "textarea":
						$this->checkTextAreaSyntax($className, $i, $property);
						break;
					case "password":
						$this->checkPasswordSyntax($className, $i, $property);
						break;
					case "select":
						$this->checkSelectSyntax($className, $i, $property);
						break;
					case "radio":
						$this->checkRadioSyntax($className, $i, $property);
						break;
					case "checkbox":
						$this->checkCheckboxSyntax($className, $i, $property);
						break;
				}
			}
		}
	}
	/**
	 * checkGeneralSyntax
	 * - General syntax for all tag &lt;property&gt;
	 * - 5 required attributes are:
	 *    +) name
	 *    +) field
	 *    +) type
	 *    +) required
	 *    +) display
	 * - Attribute 'name' and 'field' should be similar
	 * - If has error, add to array of errors
	 * @param Array $property The attributes of an &lt;property&gt; tag
	 */
	private function checkGeneralSyntax($className, $i, $property) {
		$name = " - " . $property["name"];
		// 5 required attributes
		if ($property["name"] == "") {
			$this->addError("$className - Property $i :  No 'name' attribute");
		}
		if ($property["type"] == "") {
			$this->addError("$className - Property $i $name:  No 'type' attribute");
		}
		if ($property["field"] == "") {
			$this->addError("$className - Property $i $name:  No 'field' attribute");
		}
		if ($property["required"] == "") {
			$this->addError("$className - Property $i $name:  No 'required' attribute");
		}
		if ($property["display"] == "") {
			$this->addError("$className - Property $i $name:  No 'display' attribute");
		}
		// Attribute 'name' and 'field' should be similar
		if ($property["name"] != "" && $property["field"] != "") {
			if ($property["name"] != str_replace(".", "_", $property["field"])) {
				$this->addWarning("$className - Property $i $name: Attribute 'name' and 'field' should be similar");
			}
		}
		// Check if field exist in DB
		if ($property["field"] != "") {
			global $dbcon;
			list($table, $field) = explode(".", $property["field"]);
			$sql = "SELECT $field FROM $table LIMIT 1 OFFSET 0";
			$rs = $dbcon->Execute($sql);
			if ($rs == null) {
				$this->addWarning("$className - Property $i $name: Attribute 'field' specifies an unexisting column");
			}
		}
	}
	/**
	 * checkTextSyntax
	 * - Validate the text syntax, add error to error array if exits error.
	 * @param Array $property The attributes of an &lt;property&gt; tag
	 * @return void
	 */
	private function checkTextSyntax($className, $i, $property) {
		$name = " - " . $property["name"];
		// Check if size is not a number
		if ($property["size"] != "") {
			$size = $property["size"];
			if (!preg_match("/^[0-9]+$/", $size)) {
				$this->addError("$className - Property $i $name: Attribute 'size' is not a number");
			}
		}
		// Check if min-size is not a number
		if ($property["min-size"] != "") {
			$size = $property["min-size"];
			if (!preg_match("/^[0-9]+$/", $size)) {
				$this->addError("$className - Property $i $name: Attribute 'min-size' is not a number");
			}
		}
	}
	/**
	 * checkTextAreaSyntax
	 * - Validate the text area syntax, add error to error array if exits error.
	 * @param Array $property The attributes of an &lt;property&gt; tag
	 * @return void
	 */
	private function checkTextAreaSyntax($className, $i, $property) {
		$name = " - " . $property["name"];
		// Row and col is required
		if ($property["row"] == "") {
			$this->addError("$className - Property $i $name: Attribute 'row' is required");
		}
		if ($property["col"] == "") {
			$this->addError("$className - Property $i $name: Attribute 'col' is required");
		}
		// Check if size is not a number
		if ($property["size"] != "") {
			$size = $property["size"];
			if (!preg_match("/^[0-9]+$/", $size)) {
				$this->addError("$className - Property $i $name: Attribute 'size' is not a number");
			}
		}
		// Check if min-size is not a number
		if ($property["min-size"] != "") {
			$size = $property["min-size"];
			if (!preg_match("/^[0-9]+$/", $size)) {
				$this->addError("$className - Property $i $name: Attribute 'min-size' is not a number");
			}
		}
	}
	/**
	 * checkPasswordSyntax
	 * - Validate the password syntax, add error to error array if exits error.
	 * @param Array $property The attributes of an &lt;property&gt; tag
	 * @return void
	 */
	private function checkPasswordSyntax($className, $i, $property) {
		$name = " - " . $property["name"];
		// Check if size is not a number
		if ($property["size"] != "") {
			$size = $property["size"];
			if (!preg_match("/^[0-9]+$/", $size)) {
				$this->addError("$className - Property $i $name: Attribute 'size' is not a number");
			}
		}
		// Check if min-size is not a number
		if ($property["min-size"] != "") {
			$size = $property["min-size"];
			if (!preg_match("/^[0-9]+$/", $size)) {
				$this->addError("$className - Property $i $name: Attribute 'min-size' is not a number");
			}
		}
	}
	/**
	 * checkSelectSyntax
	 * - Validate the select syntax, add error to error array if exits error.
	 * @param Array $property The attributes of an &lt;property&gt; tag
	 * @return void
	 */
	private function checkSelectSyntax($className, $i, $property) {
		$name = " - " . $property["name"];
		if ($property["list"] == "" && $property["codeDef"] == "") {
			$this->addError("$className - Property $i $name: Must declare 'list' or 'codeDef'");
		}
	}
	/**
	 * checkRadioSyntax
	 * - Validate the radio syntax, add error to error array if exits error.
	 * @param Array $property The attributes of an &lt;property&gt; tag
	 * @return void
	 */
	private function checkRadioSyntax($className, $i, $property) {
		$name = " - " . $property["name"];
		if ($property["list"] == "" && $property["codeDef"] == "") {
			$this->addError("$className - Property $i $name: Must declare 'list' or 'codeDef'");
		}
		if ($property["col"] == "") {
			$this->addError("$className - Property $i $name: Attribute 'col' is required");
		}
	}
	/**
	 * checkCheckboxSyntax
	 * - Validate the checkbox syntax, add error to error array if exits error.
	 * @param Array $property The attributes of an &lt;property&gt; tag
	 * @return void
	 */
	private function checkCheckboxSyntax($className, $i, $property) {
		$name = " - " . $property["name"];
		if ($property["list"] == "" && $property["codeDef"] == "") {
			$this->addError("$className - Property $i $name: Must declare 'list' or 'codeDef'");
		}
		if ($property["col"] == "") {
			$this->addError("$className - Property $i $name: Attribute 'col' is required");
		}
	}
}
?>